import { findClosestPoint, makeAngleLines, makePlane } from '@/commands/util';
import { RenderBase } from '@/common/cmdBase/renderBase';
import { PointEnum, pointsManager } from '@/common/preview';
import { createAxis, nmAppErrorLog } from '@/common/utils';
import { surfProcess } from '@/domain';
import { EntityInfo, EntityPartType, THREE } from '@amcax/web-render';
import { useFocusStore } from 'nextcae-base/src/common/store';
import { Box } from 'nextcae-base/src/dialogs/component/Box';
import { FormContent } from 'nextcae-base/src/dialogs/component/FormContent';
import { useEffect, useRef, useState } from 'react';
import { schema, uiSchema } from '../data';
import { excelType, TableData } from '../type';
import { ButtonPointsGroups } from './ButtonTableGroups';
import { TableComponent } from './TableDropDownComponent';
import { Footer } from './TableFooter';

export function TableCsvComponentDialog(props: excelType) {
  // 聚焦的id，当不在source(拟合曲面)上时，拾取面的点或表格的点进行添加或编辑
  const { focusId } = useFocusStore();
  // 渲染、拾取相关的功能类
  const renderBase = useRef<RenderBase>(new RenderBase());
  const [uploadTableData, setUploadTableData] = useState([]);
  const [newTableData, setNewTableData] = useState<TableData[]>([]);
  const [formData, setFormData] = useState<any>({
    RefDir: [0, 0, 1],
    RefOrigin: [0, 0, 0],
    RefAglDir: [1, 0, 0],
  });
  // 当formData发生变化时，需要全量请求后端计算坐标
  const [formDataChanged, setFormDataChanged] = useState<boolean>(false);
  // 选中的行索引，用于高亮
  const [selectedKey, setSelectedKey] = useState<number>(-1);
  // 表格每一项对应的点坐标，用于渲染和交互（吸附）
  const tablePoints = useRef<THREE.Vector3Tuple[]>([]);
  // 吸附点信息
  const snapPoint = useRef<{
    point: THREE.Vector3Tuple;
    index: number;
  }>(null);

  // 组件退出，清理数据
  useEffect(() => {
    return () => {
      renderBase.current.clearAssisMgr();
    };
  }, []);
  // 切换到表格时，也能拾取，这时候就是拾取面上的点，然后点击插入表格
  useEffect(() => {
    if (focusId !== 'root_Selection_source') {
      renderBase.current.enablePick = true;
      renderBase.current.pickType = EntityPartType.face;
      renderBase.current.interactionMgr.addHoveredListener(onHovered);
      renderBase.current.interactionMgr.addClickListener(onClick);
      return () => {
        renderBase.current.interactionMgr.removeHoveredListener(onHovered);
        renderBase.current.interactionMgr.removeClickListener(onClick);
      };
    }
    return () => {};
  }, [focusId]);
  // 监听数据变化，渲染基准平面、角度线和点
  useEffect(() => {
    renderBase.current.assisMgr.group.clear();
    // 判断RefDir、RefAglDir、RefOrigin的x/y/z是否为null
    const { RefDir, RefOrigin, RefAglDir } = formData;
    if (
      RefDir.length === 0 ||
      RefOrigin.length === 0 ||
      RefAglDir.length === 0
    ) {
      return;
    }

    // 计算模型的包围盒，用来设置线、平面的大小
    const meshMgr = renderBase.current.meshMgr;
    const box = new THREE.Box3().setFromObject(meshMgr.group);

    // 根据轴向方向和轴向起点创建基准轴
    const refOrigin = new THREE.Vector3(
      RefOrigin[0],
      RefOrigin[1],
      RefOrigin[2],
    );
    const refDir = new THREE.Vector3(RefDir[0], RefDir[1], RefDir[2]);
    const refAglDir = new THREE.Vector3(
      RefAglDir[0],
      RefAglDir[1],
      RefAglDir[2],
    );
    const size = box.getSize(new THREE.Vector3());
    const length = Math.max(size.x, size.y, size.z);
    const arrow = createAxis(
      refOrigin,
      refDir,
      0xff6b6b,
      length * 1.2,
      2,
      length / 10,
      length / 20,
    );
    // 渲染基准平面
    const plane = makePlane(refOrigin, refDir, size);
    renderBase.current.assisMgr.group.add(arrow, plane);
    // 渲染角度线
    if (newTableData.length > 0) {
      const line = makeAngleLines(
        refOrigin,
        refDir,
        refAglDir,
        newTableData.map(({ angles }) => angles),
        length,
      );
      renderBase.current.assisMgr.group.add(line);
      // 渲染点
      tablePoints.current = newTableData
        .filter((item) => item.point?.length === 3)
        .map(
          (item) =>
            [item.point[0], item.point[1], item.point[2]] as THREE.Vector3Tuple,
        );
      pointsManager().renderPoints(
        tablePoints.current,
        PointEnum.TEMPP,
        undefined,
        2, // 实心圆
        10,
      );
    }

    renderBase.current.render();
  }, [newTableData, formData]);
  // 当formData发生变化时，需要全量请求后端计算坐标
  useEffect(() => {
    if (formDataChanged) {
      setFormDataChanged(false);
      // 导入数据，且formData合法，请求后端计算坐标
      if (validateFormData(formData) && newTableData.length > 0) {
        const heightArray: number[] = [];
        const anglesArray: number[] = [];
        for (let i = 0; i < newTableData.length; i++) {
          const tableData = newTableData[i];
          heightArray.push(tableData.height);
          anglesArray.push(tableData.angles);
        }
        surfProcess
          .surfacePtsByCoord({
            surface: formData.Selection?.source?.[0]?.dxid,
            refDir: formData.RefDir,
            refOrigin: formData.RefOrigin,
            refAglDir: formData.RefAglDir,
            heights: heightArray,
            angles: anglesArray,
          })
          .then(({ intersections, points }) => {
            for (let i = 0; i < newTableData.length; i++) {
              const item = newTableData[i];
              if (intersections?.[i]) {
                item.point = [
                  points[i * 3],
                  points[i * 3 + 1],
                  points[i * 3 + 2],
                ];
              }
            }
            setNewTableData([...newTableData]);
          });
      }
    }
  }, [formDataChanged, newTableData, formData]);
  // 校验formData是否合法
  const validateFormData = (fData) => {
    const { RefDir, RefOrigin, RefAglDir, Selection } = fData;
    if (
      Selection?.source?.length === 0 ||
      RefDir.length === 0 ||
      RefOrigin.length === 0 ||
      RefAglDir.length === 0
    ) {
      return false;
    }
    return true;
  };
  // 拾取面的点，判断是否和已有的点重复（吸附）并能选中高亮表格行和插入
  const onHovered = (entity: EntityInfo) => {
    if (entity?.point) {
      snapPoint.current = findClosestPoint(entity.point, tablePoints.current);
      const movePoint = snapPoint.current?.point ?? entity.point;
      if (snapPoint.current?.index !== -1) {
        // 选中高亮表格行
        setSelectedKey(snapPoint.current.index);
      }
      pointsManager().renderPoints([movePoint], PointEnum.MOVEP);
    } else {
      pointsManager().removePoints(PointEnum.MOVEP);
    }
  };
  // 点击，插入点
  const onClick = (entity: EntityInfo, selected: boolean) => {
    // 如果是选中，则取消选中；TODO 待优化应该就不能被选中，添加一个beforeSelect回调？
    if (selected) {
      renderBase.current.meshMgr.setEntitySelected(
        false,
        entity.dxid,
        entity.type,
        entity.idx,
      );
    }
    if (entity) {
      if (snapPoint.current?.index !== -1) {
        // 选中了已有的数据，聚焦高亮行
        // TODO 高度并滚动到选中行
      } else {
        // 保留小数点后两位
        const point = entity.point.map((item) => Number(item.toFixed(2)));
        // 插入新数据，最好能自动聚焦到新插入的行的厚度处，让用户输入
        // 根据点，计算截面值和角度值
        surfProcess
          .cylindricalCoord({
            surface: entity.dxid as string,
            refDir: formData.RefDir,
            refOrigin: formData.RefOrigin,
            refAglDir: formData.RefAglDir,
            points: point,
          })
          .then((res) => {
            const { heights, angles } = res;
            if (heights?.length > 0 && heights.length === angles?.length) {
              setUploadTableData(
                heights.map((h, index) => ({
                  height: h.toFixed(2),
                  angles: angles[index].toFixed(2),
                  thickness: null,
                  point: point,
                })),
              );
            } else {
              nmAppErrorLog('返回数据格式错误，数据为空或长度不一致', res);
            }
          });
      }
    }
  };
  const handleImport = (e) => {
    const fileInput = e.target; // 这是input元素
    const file = fileInput.files[0]; // 获取选择的文件
    if (!file) return;
    // 文件解析数据方法
    const reader = new FileReader();
    reader.onload = async (readerEvent) => {
      const content = String(readerEvent.target?.result);
      await csvToTableData(content);
    };
    reader.readAsText(file);
  };
  // 将 txt/csv 转成 tableData 类型
  const csvToTableData = async (csv: string) => {
    // 校验数据格式
    const lines = csv.split(/\r\n|\n/).filter((line) => line.trim() !== '');
    // 表格数据
    const tableDataArray: TableData[] = [];
    const heightArray: number[] = [];
    const anglesArray: number[] = [];
    for (let i = 0; i < lines.length; i++) {
      const item = lines[i];
      const line = item.split(',');
      const tableData: TableData = {
        height: Number(line[0]),
        angles: Number(line[1]),
        thickness: Number(line[2]),
      };
      heightArray.push(tableData.height);
      anglesArray.push(tableData.angles);
      tableDataArray.push(tableData);
    }
    // 导入数据，且formData合法，请求后端计算坐标
    if (validateFormData(formData) && heightArray.length > 0) {
      const { intersections, points } = await surfProcess.surfacePtsByCoord({
        surface: formData.Selection?.source?.map((item) => item.dxid)[0],
        refDir: formData.RefDir,
        refOrigin: formData.RefOrigin,
        refAglDir: formData.RefAglDir,
        heights: heightArray,
        angles: anglesArray,
      });
      for (let i = 0; i < tableDataArray.length; i++) {
        const item = tableDataArray[i];
        if (intersections[i]) {
          item.point = [points[i * 3], points[i * 3 + 1], points[i * 3 + 2]];
        }
      }
    }
    setUploadTableData(tableDataArray);
  };

  // 导出csv
  const handleExport = () => {
    if (newTableData.length === 0) {
      return;
    }
    const rows = newTableData
      .map((item) => {
        return `${item.height ?? ''},${item.angles ?? ''},${item.thickness ?? ''}`;
      })
      .join('\n');

    const blob = new Blob([rows], { type: 'text/csv;charset=utf-8;' });
    const link = document.createElement('a');
    link.href = URL.createObjectURL(blob);
    link.download = 'points.csv';
    link.click();
  };

  // 删除所有行
  const handleDeleteAll = () => {
    pointsManager().removePoints();
    setUploadTableData([]); // 清空上传的数据（如果有）
    setNewTableData([]); // 重置为空数据
  };

  // 数据发生改变
  const handleDataChange = async (data: TableData[], editKey?: number) => {
    if (editKey !== undefined) {
      // 编辑行，判断是否需要计算坐标
      const item = data[editKey];
      if (item.height !== null && item.angles !== null) {
        // 有坐标，跳过
        if (!item.point) {
          // 没有坐标，请求接口计算坐标，并保存下来，避免重复计算
          const { points } = await surfProcess.surfacePtsByCoord({
            surface: formData.Selection?.source?.map((item) => item.dxid)[0],
            refDir: formData.RefDir,
            refOrigin: formData.RefOrigin,
            refAglDir: formData.RefAglDir,
            heights: [item.height],
            angles: [item.angles],
          });
          item.point = points as THREE.Vector3Tuple;
        }
      } else {
        // 没有height或angles，坐标设为null，也就不渲染point了
        item.point = null;
      }
    }
    // data 筛选出不为空的行
    const newData = data.filter(
      (item) => item.height !== null && item.angles !== null,
    );
    setNewTableData(newData);
  };

  // 确定按钮
  const handleTableSubmit = async () => {
    // 处理数据
    const processedData = {
      height: newTableData.map((item) => item.height),
      angles: newTableData.map((item) => item.angles),
      thickness: newTableData.map((item) => item.thickness),
    };
    const { Selection, RefDir, RefOrigin, RefAglDir } = formData;
    const params = {
      surface: Selection?.source?.map((item) => item.dxid)[0],
      refDir: [RefDir[0], RefDir[1], RefDir[2]],
      refOrigin: [RefOrigin[0], RefOrigin[1], RefOrigin[2]],
      refAglDir: [RefAglDir[0], RefAglDir[1], RefAglDir[2]],
      ...processedData,
    };
    await surfProcess.deform(params);
  };

  return (
    <Box {...props}>
      <>
        <FormContent
          schema={schema}
          extraUiSchema={uiSchema}
          formData={formData}
          fields={{}}
          onChange={(data) => {
            setFormDataChanged(true);
            setFormData(data.formData);
          }}
          footerChildren={<></>}
        />
        <ButtonPointsGroups
          onImport={handleImport}
          onExport={handleExport}
          onDeleteAll={handleDeleteAll}
          btnDisabled={newTableData.length === 0}
        />
        <TableComponent
          selectedKey={selectedKey}
          initialData={uploadTableData}
          onDataChange={handleDataChange}
        />
        <Footer
          onClose={() => {
            pointsManager().removePoints();
            props.onClose();
          }}
          handleSubmit={handleTableSubmit}
          btnDisabled={
            newTableData.length === 0 ||
            formData?.Selection?.source?.length === 0 ||
            formData?.RefDir.length === 0 ||
            formData?.RefOrigin.length === 0 ||
            formData?.RefAglDir.length === 0
          }
        />
      </>
    </Box>
  );
}
